﻿//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//   Copyright (c) 2013, Intergraph Corporation. All rights reserved.
//
//   PSL_VBM.cs
//   PSL,Ingr.SP3D.Content.Support.Symbols.PSL_VBM
//   Author       :BS   
//   Creation Date:21.08.2013  
//   Description:

//   Change History:
//   dd.mmm.yyyy     who     change description
//   -----------     ---     ------------------
//   21.08.2013      BS      CR-CP-232036,232037,232038,232039,232040 Convert HS_PSL VB Project to C# .Net    
//   30-Dec-2014    PVK          TR-CP-264951	Resolve P3 coverity issues found in November 2014 report
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Ingr.SP3D.Common.Middle;
using Ingr.SP3D.Common.Middle.Services;
using Ingr.SP3D.ReferenceData.Middle;
using Ingr.SP3D.Support.Middle;

namespace Ingr.SP3D.Content.Support.Symbols
{
    //-----------------------------------------------------------------------------------
    //Namespace of this class is Ingr.SP3D.Content.Support.Symbols
    //It is recommended that customers specify namespace of their symbols to be
    //CompanyName.SP3D.Content.Specialization.
    //It is also recommended that if customers want to change this symbol to suit their
    //requirements, they should change namespace/symbol name so the identity of the modified
    //symbol will be different from the one delivered by Intergraph.
    //-----------------------------------------------------------------------------------

    [CacheOption(CacheOptionType.Cached)]
    [SymbolVersion("1.0.0.0")]
    public class PSL_VBM : HangerComponentSymbolDefinition
    {

        //DefinitionName/ProgID of this symbol is "PSL,Ingr.SP3D.Content.Support.Symbols.PSL_VBM"

        #region "Definition of Inputs"
        [InputCatalogPart(1)]
        public InputCatalogPart PartInput;
        [InputDouble(2, "MAX_TRAVEL", "MAX_TRAVEL", 0.999999)]
        public InputDouble MAX_TRAVEL;
        [InputDouble(3, "WORKING_TRAV_DOWN", "WORKING_TRAV_DOWN", 0.999999)]
        public InputDouble WORKING_TRAV_DOWN;
        [InputDouble(4, "WORKING_TRAV_UP", "WORKING_TRAV_UP", 0.999999)]
        public InputDouble WORKING_TRAV_UP;
        [InputDouble(5, "TOTAL_TRAV1", "TOTAL_TRAV1", 0.999999)]
        public InputDouble TOTAL_TRAV1;
        [InputDouble(6, "MIN_TRAVEL", "MIN_TRAVEL", 0.999999)]
        public InputDouble MIN_TRAVEL;
        [InputString(7, "SIZE", "SIZE", "No Value")]
        public InputString SIZE;
        [InputDouble(8, "OPER_LOAD", "OPER_LOAD", 0.999999)]
        public InputDouble OPER_LOAD;
        #endregion

        #region "Definitions of Aspects and their Outputs"
        [Aspect("Symbolic", "Symbolic Aspect", AspectID.SimplePhysical)]
        [SymbolOutput("Port1", "Port1")]
        [SymbolOutput("Port2", "Port2")]
        [SymbolOutput("TURNB", "TURNB")]
        [SymbolOutput("ROD", "ROD")]
        [SymbolOutput("ARM", "ARM")]
        [SymbolOutput("BASE", "BASE")]
        [SymbolOutput("BODY", "BODY")]
        [SymbolOutput("PLATE", "PLATE")]
        public AspectDefinition m_Symbolic;

        #endregion

        #region "Construct Outputs"

        /// <summary>
        /// Construct symbol outputs in aspects.
        /// </summary>
        /// <remarks></remarks>
        protected override void ConstructOutputs()
        {
            try
            {
                Part part = (Part)PartInput.Value;
                string size = SIZE.Value;
                double minTravel = MIN_TRAVEL.Value;
                double maxTravel = MAX_TRAVEL.Value;
                double operLoad = OPER_LOAD.Value;

                double workingTraveldown = WORKING_TRAV_DOWN.Value;
                double workingTravelup = WORKING_TRAV_UP.Value;

                double maxOperatingLoad = PSLSymbolServices.GetDataByCondition("PSL_CON_LOAD", "IJUAHgrPSL_CON_LOAD", "MAX_LOAD", "IJUAHgrPSL_CON_LOAD", "SIZE", size);
                double minOperatingLoad = PSLSymbolServices.GetDataByCondition("PSL_CON_LOAD", "IJUAHgrPSL_CON_LOAD", "MIN_LOAD", "IJUAHgrPSL_CON_LOAD", "SIZE", size);

                maxOperatingLoad = MiddleServiceProvider.UOMMgr.ConvertDBUtoUnit(UnitType.Force, maxOperatingLoad, UnitName.FORCE_NEWTON);
                minOperatingLoad = MiddleServiceProvider.UOMMgr.ConvertDBUtoUnit(UnitType.Force, minOperatingLoad, UnitName.FORCE_NEWTON);

                if (operLoad < minOperatingLoad - 0.0001 || operLoad > maxOperatingLoad + 0.0001)
                {
                    ToDoListMessage = new ToDoListMessage(ToDoMessageTypes.ToDoMessageWarning,"Operating load should be between " + minOperatingLoad.ToString() + "N and " + maxOperatingLoad.ToString() + "N.");
                    operLoad = minOperatingLoad;
                }
                minTravel = MiddleServiceProvider.UOMMgr.ConvertDBUtoUnit(UnitType.Distance, minTravel, UnitName.DISTANCE_MILLIMETER);
                maxTravel = MiddleServiceProvider.UOMMgr.ConvertDBUtoUnit(UnitType.Distance, maxTravel, UnitName.DISTANCE_MILLIMETER);

                double moment = PSLSymbolServices.GetDataByCondition("PSL_CON_LOAD", "IJUAHgrPSL_CON_LOAD", "WR_MAX", "IJUAHgrPSL_CON_LOAD", "SIZE", size);
                moment = MiddleServiceProvider.UOMMgr.ConvertDBUtoUnit(UnitType.Distance, moment, UnitName.DISTANCE_MILLIMETER);

                double workingTravelDownConv = MiddleServiceProvider.UOMMgr.ConvertDBUtoUnit(UnitType.Distance, workingTraveldown, UnitName.DISTANCE_MILLIMETER);
                double workingTravelUpConv = MiddleServiceProvider.UOMMgr.ConvertDBUtoUnit(UnitType.Distance, workingTravelup, UnitName.DISTANCE_MILLIMETER);

                double calculatedTotalTravel = 10 * (int)(moment * 100 / operLoad + 0.5);

                //--- make 301.xxx to 300 for example; otherwise it generates error
                calculatedTotalTravel = Math.Round(calculatedTotalTravel / 1000.0, 2) * 1000;

                double totalActualTravel = workingTravelDownConv + workingTravelUpConv;
                if ((totalActualTravel + 25 <= calculatedTotalTravel) && (calculatedTotalTravel >= minTravel) && (calculatedTotalTravel <= maxTravel))
                { }
                else
                {
                    ToDoListMessage = new ToDoListMessage(ToDoMessageTypes.ToDoMessageError, PSLLocalizer.GetString(PSLSymbolResourceIDs.ErrInvalidSpringSize, "Selected spring size is not suitable for load and travel specified."));
                    return;
                }
                double totalTravel1 = calculatedTotalTravel;
                double totalTravel = totalTravel1;
                const double PI = 3.14159265359;
                double setPosition = (totalTravel + workingTravelUpConv - workingTravelDownConv) / 2;
                double leverLength = totalTravel / (Math.Sin(35 * PI / 180) + Math.Sin(10 * PI / 180));
                double leverAngleOffset = (35 * PI / 180 - Math.Asin((leverLength * Math.Sin(35 * PI / 180) - setPosition) / leverLength)) * 180 / PI;
                setPosition = MiddleServiceProvider.UOMMgr.ConvertUnitToDBU(UnitType.Distance, setPosition, UnitName.DISTANCE_MILLIMETER);
                leverLength = MiddleServiceProvider.UOMMgr.ConvertUnitToDBU(UnitType.Distance, leverLength, UnitName.DISTANCE_MILLIMETER);

                if (HgrCompareDoubleService.cmpdbl((int)(totalTravel1 / 10) * 10.0, totalTravel1) == false)
                    totalTravel = (int)(totalTravel1 / 10) * 10.0 + 10.0;

                totalTravel = MiddleServiceProvider.UOMMgr.ConvertUnitToDBU(UnitType.Distance, totalTravel, UnitName.DISTANCE_MILLIMETER);

                Dictionary<KeyValuePair<string, string>, Object> parameter = new Dictionary<KeyValuePair<string, string>, Object>();
                parameter.Add(new KeyValuePair<string, string>("IJUAHgrPSL_CONSTANTS", "SIZE"), size.Trim());
                parameter.Add(new KeyValuePair<string, string>("IJUAHgrPSL_CONSTANTS", "TOTAL_TRAV"), totalTravel);

                double XB = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "XB", parameter);
                double XC = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "XC", parameter);
                double E = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "E", parameter);
                double rodDiamater = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "ROD_DIA", parameter);
                double FA = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "FA", parameter);
                double FE = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "FE", parameter);
                double FB = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "FB", parameter);
                double FC = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "FC", parameter);
                double TA = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "TA", parameter);
                double SD = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "SD", parameter);
                double FF = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "FF", parameter);
                double XA = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "XA", parameter);
                double FX = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "FX", parameter);
                double FZ = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "FZ", parameter);
                double J = (double)PSLSymbolServices.GetDataByMultipleConditions("PSL_CONSTANTS", "IJUAHgrPSL_CONSTANTS", "J6", parameter);

                double J6 = J - setPosition;
                double vert = leverLength * Math.Sin((35 - leverAngleOffset) * PI / 180);
                double D = leverLength * Math.Cos((35 - leverAngleOffset) * PI / 180);
                double C = leverLength;

                double angle = 35 - leverAngleOffset;
                double cylinderLength = MiddleServiceProvider.UOMMgr.ConvertUnitToDBU(UnitType.Distance, 250, UnitName.DISTANCE_MILLIMETER);
                double locZ = MiddleServiceProvider.UOMMgr.ConvertUnitToDBU(UnitType.Distance, 100, UnitName.DISTANCE_MILLIMETER);

                if (angle > 35)
                    ToDoListMessage = new ToDoListMessage(ToDoMessageTypes.ToDoMessageWarning, PSLLocalizer.GetString(PSLSymbolResourceIDs.ErrInvalidLeverAngle, "Lever angle cannot exceed 35 degrees. Please reset Actual Travel Up and Actual Travel Down with proper values."));

                Port port1 = new Port(OccurrenceConnection, part, "InThdRH", new Position(0, 0, 0), new Vector(1, 0, 0), new Vector(0, 0, 1));
                m_Symbolic.Outputs["Port1"] = port1;
                Port port2 = new Port(OccurrenceConnection, part, "Structure", new Position(0, D + (XB + XC) / 2.0 - XB, -J6), new Vector(1, 0, 0), new Vector(0, 0, 1));
                m_Symbolic.Outputs["Port2"] = port2;
                if (rodDiamater <= 0)
                {
                    ToDoListMessage = new ToDoListMessage(ToDoMessageTypes.ToDoMessageError, PSLLocalizer.GetString(PSLSymbolResourceIDs.ErrInvalidRodDiameterGTZ, "ROD_DIA should be greater than zero"));
                    return;
                }
                if (HgrCompareDoubleService.cmpdbl(cylinderLength , 0)==true)
                {
                    ToDoListMessage = new ToDoListMessage(ToDoMessageTypes.ToDoMessageError, PSLLocalizer.GetString(PSLSymbolResourceIDs.ErrInvalidCylinderLength, "CYL_LEN cannot be zero"));
                    return;
                }
                if (FE <= 0)
                {
                    ToDoListMessage = new ToDoListMessage(ToDoMessageTypes.ToDoMessageError, PSLLocalizer.GetString(PSLSymbolResourceIDs.ErrInvalidFEGTZ, "FE value should be greater than zero"));
                    return;
                }
                if (FB <= 0)
                {
                    ToDoListMessage = new ToDoListMessage(ToDoMessageTypes.ToDoMessageError, PSLLocalizer.GetString(PSLSymbolResourceIDs.ErrInvalidFBGTZ, "FB value should be greater than zero"));
                    return;
                }
                if (XA <= 0)
                {
                    ToDoListMessage = new ToDoListMessage(ToDoMessageTypes.ToDoMessageError, PSLLocalizer.GetString(PSLSymbolResourceIDs.ErrInvalidXAGTZ, "XA value should be greater than zero"));
                    return;
                }
                if (FZ <= 0)
                {
                    ToDoListMessage = new ToDoListMessage(ToDoMessageTypes.ToDoMessageError, PSLLocalizer.GetString(PSLSymbolResourceIDs.ErrInvalidFZGTZ, "FZ value should be greater than zero"));
                    return;
                }
                if (FF <= 0)
                {
                    ToDoListMessage = new ToDoListMessage(ToDoMessageTypes.ToDoMessageError, PSLLocalizer.GetString(PSLSymbolResourceIDs.ErrInvalidFFGTZ, "FF value should be greater than zero"));
                    return;
                }
               
                SymbolGeometryHelper symbolGeometryHelper = new SymbolGeometryHelper();
                symbolGeometryHelper.ActivePosition = new Position(0, 0, -locZ);
                symbolGeometryHelper.SetOrientation(new Vector(0, 0, 1), new Vector(0, 0, 1).GetOrthogonalVector());
                Projection3d turnB = symbolGeometryHelper.CreateCylinder(null, rodDiamater, cylinderLength);
                m_Symbolic.Outputs["TURNB"] = turnB;

                locZ = MiddleServiceProvider.UOMMgr.ConvertUnitToDBU(UnitType.Distance, 50, UnitName.DISTANCE_MILLIMETER);
                double tempNumber = MiddleServiceProvider.UOMMgr.ConvertUnitToDBU(UnitType.Distance, 50, UnitName.DISTANCE_MILLIMETER);

                symbolGeometryHelper = new SymbolGeometryHelper();
                symbolGeometryHelper.ActivePosition = new Position(0, 0, locZ);
                symbolGeometryHelper.SetOrientation(new Vector(0, 0, 1), new Vector(0, 0, 1).GetOrthogonalVector());
                Projection3d rod = symbolGeometryHelper.CreateCylinder(null, rodDiamater / 2, SD - J + E - tempNumber);
                m_Symbolic.Outputs["ROD"] = rod;

                symbolGeometryHelper = new SymbolGeometryHelper();
                symbolGeometryHelper.ActivePosition = new Position(0, 0, 0);
                Projection3d arm = symbolGeometryHelper.CreateBox(null, TA, rodDiamater * 2.0, rodDiamater * 4, 9);
                Matrix4X4 matrix = new Matrix4X4();
                matrix.Translate(new Vector(-TA, 0, -rodDiamater * 2));
                matrix.Rotate(angle * Math.PI / 180.0, new Vector(0, 1, 0), new Position(0, 0, 0));
                matrix.Translate(new Vector(D, -rodDiamater, SD - J6));
                matrix.Rotate(Math.PI / 2, new Vector(0, 0, 1), new Position(0, 0, 0));
                arm.Transform(matrix);
                m_Symbolic.Outputs["ARM"] = arm;

                Collection<Position> pointCollection = new Collection<Position>();
                pointCollection.Add(new Position(0, D - rodDiamater, -J6 + FF));
                pointCollection.Add(new Position(-FA / 2.0, D - rodDiamater + FE * 0.375, -J6 + FF));
                pointCollection.Add(new Position(-FA / 2.0, D - rodDiamater + FE * 0.625, -J6 + FF));
                pointCollection.Add(new Position(0, D - rodDiamater + FE, -J6 + FF));
                pointCollection.Add(new Position(FA / 2.0, D - rodDiamater + FE * 0.625, -J6 + FF));
                pointCollection.Add(new Position(FA / 2.0, D - rodDiamater + FE * 0.375, -J6 + FF));
                pointCollection.Add(new Position(0, D - rodDiamater, -J6 + FF));
                Projection3d baseProjection = new Projection3d(new LineString3d(pointCollection), new Vector(0, 0, 1), SD - FF - FC, true);
                m_Symbolic.Outputs["BASE"] = baseProjection;

                symbolGeometryHelper = new SymbolGeometryHelper();
                symbolGeometryHelper.ActivePosition = new Position(0, 0, 0);
                Projection3d body = symbolGeometryHelper.CreateBox(null, FE, FB, FC + FX, 9);
                matrix = new Matrix4X4();
                matrix.Translate(new Vector(D - rodDiamater, -FB / 2.0, SD - J6 - FX));
                matrix.Rotate(Math.PI / 2, new Vector(0, 0, 1), new Position(0, 0, 0));
                body.Transform(matrix);
                m_Symbolic.Outputs["BODY"] = body;

                symbolGeometryHelper = new SymbolGeometryHelper();
                symbolGeometryHelper.ActivePosition = new Position(0, 0, 0);
                Projection3d plate = symbolGeometryHelper.CreateBox(null, XA, FZ, FF, 9);
                matrix = new Matrix4X4();
                matrix.Translate(new Vector(D - XB + (XB + XC) / 2.0 - XA / 2.0, -FZ / 2.0, -J6));
                matrix.Rotate(Math.PI / 2, new Vector(0, 0, 1), new Position(0, 0, 0));
                plate.Transform(matrix);
                m_Symbolic.Outputs["PLATE"] = plate;
            }
            catch
            {
                if (base.ToDoListMessage == null) //Check ToDoListMessgae created already or not
                {
                    ToDoListMessage = new ToDoListMessage(ToDoMessageTypes.ToDoMessageError, PSLLocalizer.GetString(PSLSymbolResourceIDs.ErrConstructOutputs, "Error in ConstructOutputs of PSL_VBM"));
                    return;
                }
            }
        }
        #endregion
    }
}
